#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <semaphore.h>
#include "LockGuard.hpp"
using namespace std;
const int defaultsize = 20;
template <class T>
class ringqueue {
    private :
    // P V操作
    void P(sem_t& sem) {
        sem_wait(&sem);
    }

    void V(sem_t& sem) {
        sem_post(&sem);

    }
    public :
    ringqueue(const int size = defaultsize) 
        :_size(size)
        ,_ringqueue(size)
        ,_c_step(0)
        ,_p_step(0)

    {
        // 初始化信号量
        sem_init(&_space_sem, 0, size);
        sem_init(&_data_sem, 0, 0);

        // 初始化锁
        pthread_mutex_init(&_p_mutex, nullptr);
        pthread_mutex_init(&_c_mutex, nullptr);

    }

    void Push(const T& in) {
        // 生产
        // 先申请空间
        P(_space_sem);
        {
            // 加锁
            LockGuard Lock(&_p_mutex);
            _ringqueue[_p_step] = in;
            _p_step++;
            _p_step %= _size;            
        }

        // 加上数据
        V(_data_sem);

    }
    void Pop(T* out) {
        // 消费
        // 先申请数据
        P(_data_sem); 
        // 原则上，现申请锁或者现申请信号量都可以，但是现申请信号量会比先申请所更高效，这就好比让让大多数人先买好票再一个一个进入
        {
            // 加锁
            LockGuard Lock(&_c_mutex);
            *out = _ringqueue[_c_step];
            _c_step++;
            _c_step %= _size;          
        }
        // 减去空间
        V(_space_sem);
    }

    ~ringqueue() {
        // 销毁信号量
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);

        // 销毁锁
        pthread_mutex_destroy(&_p_mutex);
        pthread_mutex_destroy(&_c_mutex);

    }
    private :
    vector<T> _ringqueue; // 环形队列
    int _size; // 环形队列的长度
    int _p_step; // 生产者的生产位置
    int _c_step; // 消费者的消费位置

    sem_t _space_sem; // 空间信号量
    sem_t _data_sem; // 数据信号量
    pthread_mutex_t _p_mutex;
    pthread_mutex_t _c_mutex;

};